﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Text;
using System.Drawing;
using System.Reflection;
using System.IO;
using System.Xml;
using log4net;
using System.Net;

namespace UPNP.IO
{
	public class Device
	{
		public const int DefaultIconSize = 32;

		protected readonly ILog _log = LogManager.GetLogger(typeof(Device));
		protected readonly List<Device> _children = new List<Device>();
        protected readonly List<DeviceService> _services = new List<DeviceService>();
	    protected readonly DeviceDom.Device _dom;

        public string SchemaId
        {
            get { return _dom.OwnerDom.SchemaId;}
        }

		public IList<Device> Children 
		{
			get { return _children.AsReadOnly(); }
		}

        public string Description
        {
            get { return _dom.ModelDescription; }
        }

        public string FriendlyName
        {
            get { return _dom.FriendlyName; }
        }

		public bool HasChildren 
		{
			get { return (_children.Count > 0); }
		}

		public bool IsRootDevice 
		{
            get { return (this.ParentDevice == null); }
		}

		public string ManufacturerName
		{
			get { return _dom.Manufacturer;}
		}

		public Uri ManufacturerURL
		{
			get { return _dom.ManufacturerUrl; }
		}
		
		public string ModelName 
		{
			get { return _dom.ModelName; }
		}
		
		public string ModelNumber 
		{
			get { return _dom.ModelNumber; }
		}
		
		public Uri ModelURL 
		{
			get { return _dom.ModelUrl; }
		}

        public Device ParentDevice
        {
            get; private set;
        }

		public Uri PresentationURL
		{
            get { return this.RootDevice._dom.PresentationUrl; }
		}

        public RootDevice RootDevice
        {
            get; private set;
        }
		
		public IList<DeviceService> Services
		{
			get { return _services.AsReadOnly(); }
		}
		
		public string Type
		{
            get { return _dom.DeviceTypeId; }
		}

		public string UniqueDeviceName
		{
            get { return _dom.DeviceName; }
		}
		
		public string UPC
		{
            get { return _dom.UPC; }
		}

		public Bitmap Icon
		{
			get
			{
				// return generic icon
				return Properties.Resources.imgGeneric_Device;
			}
		}

		/// <summary>
		/// retrieves all services including 
		/// those of all child devices
		/// </summary>
		public IList<DeviceService> GetServicesRecursive()
		{
			var services = new List<DeviceService>();
			var q = new Queue<Device>();

			q.Enqueue(this);

			while (q.Count > 0)
			{
				var d = q.Dequeue();

				services.AddRange(d.Services);

				foreach (var c in d.Children)
					q.Enqueue(c);
			}

			return services.AsReadOnly();
		}

		/// <summary>
		/// retrieves a specific service by its interface
		/// recursively
		/// </summary>
		public T GetServiceRecursive<T>() where T : class
		{
			var q = new Queue<Device>();

			q.Enqueue(this);

			while (q.Count > 0)
			{
				var d = q.Dequeue();

				foreach (var s in d.Services)
				{
					var ss = s as T;

					if (ss != null)
						return ss;
				}

				foreach (var c in d.Children)
					q.Enqueue(c);
			}

			return null;
		}

        protected Device(Device parent, DeviceDom.Device dev)
		{
            Contract.Requires(dev != null);
            Contract.Requires(parent == null || parent.RootDevice != null);

            _dom = dev;

            // gather values
            this.ParentDevice = parent;
            this.RootDevice = (this as RootDevice) ?? parent.RootDevice;

            // create services
            foreach (var s in dev.Services)
            {
                _services.Add(new DeviceService(this, s));
            }

            // create children
            foreach (var c in dev.ChildDevices)
            {
                _children.Add(new Device(this, c));
            }
		}
		
	}
}
